﻿
namespace starLiGHT.Components.SandboxManager
{
    #region Using Statements
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Reflection;
    using System.Text;
    using Microsoft.Xna.Framework;
    #endregion

    public static class SandboxManager
    {
        private static Dictionary<Type, int> nameToTestId;
        private static int numTests;
        private static int actTest;
        private static string singleTest = string.Empty;

        // static SandboxManager()
        // {
        // }

        public static string SingleTest
        {
            get { return singleTest; }
            set { singleTest = value; }
        }

        public static void Initialize(Microsoft.Xna.Framework.Game game)
        {
            nameToTestId = new Dictionary<Type, int>();

#if WINDOWS
            foreach (Type t in GetTypesWith<SandboxTestAttribute>(true))
            {
                nameToTestId.Add(t, numTests++);
            }
#else
            AddTestsFromAssembly(game.GetType().Assembly);
#endif
        }

        public static void Initialize(Assembly asm)
        {
            nameToTestId = new Dictionary<Type, int>();
            AddTestsFromAssembly(asm);
        }

        public static void AddTestsFromAssembly(Assembly asm)
        {
            foreach (Type t in GetTypesWith<SandboxTestAttribute>(true, asm))
            {
                nameToTestId.Add(t, numTests++);
            }
        }

        public static bool ContainsTest(string testName)
        {
            foreach (Type testKey in nameToTestId.Keys)
            {
                if (testName.Equals(testKey.Name, StringComparison.CurrentCultureIgnoreCase))
                {
                    return true;
                }
            }

            return false;
        }

        public static SandboxTest getTestByName(Microsoft.Xna.Framework.Game game, string name)
        {
            if (string.IsNullOrEmpty(name))
            {
                throw new ArgumentNullException("name");
            }

            if (game == null)
            {
                throw new ArgumentNullException("game");
            }

            foreach (Type t in nameToTestId.Keys)
            {
                if (t.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase))
                {
                    int testId = nameToTestId[t];
                    return getTestById(game, testId);
                }
            }

            throw new ArgumentException("unknown test name: " + name);
        }

        public static SandboxTest getTestById(Microsoft.Xna.Framework.Game game, int id)
        {
            if (id < 0 || id > numTests)
            {
                throw new ArgumentOutOfRangeException("id");
            }

            if (game == null)
            {
                throw new ArgumentNullException("game");
            }

            string testName = string.Empty;

            foreach (KeyValuePair<Type, int> kvp in nameToTestId)
            {
                if (kvp.Value.Equals(id))
                {
                    return Activator.CreateInstance(kvp.Key) as SandboxTest;
                }
            }

            throw new ArgumentException("unknown test id: " + id);
        }

        public static SandboxTest getActTest(Microsoft.Xna.Framework.Game game)
        {
            if (game == null)
            {
                throw new ArgumentNullException("game");
            }

            if (string.IsNullOrEmpty(singleTest))
            {
                return getTestById(game, actTest);
            }
            else
            {
                return getTestByName(game, singleTest);
            }
        }

        public static SandboxTest getNextTest(Microsoft.Xna.Framework.Game game)
        {
            if (game == null)
            {
                throw new ArgumentNullException("game");
            }

            if (string.IsNullOrEmpty(singleTest))
            {
                if (++actTest >= numTests)
                {
                    actTest = 0;
                }

                return getTestById(game, actTest);
            }
            else
            {
                return getTestByName(game, singleTest);
            }
        }

        public static SandboxTest getPreviousTest(Microsoft.Xna.Framework.Game game)
        {
            if (game == null)
            {
                throw new ArgumentNullException("game");
            }

            if (string.IsNullOrEmpty(singleTest))
            {
                if (actTest-- <= 0)
                {
                    actTest = numTests - 1;
                }

                return getTestById(game, actTest);
            }
            else
            {
                return getTestByName(game, singleTest);
            }
        }

        private static IEnumerable<Type> GetTypesWith<TAttribute>(bool inherit, Assembly executingAssembly) where TAttribute : System.Attribute
        {
            return from t in executingAssembly.GetTypes()
                   where t.IsDefined(typeof(TAttribute), inherit)
                   select t;
        }

#if WINDOWS
        private static IEnumerable<Type> GetTypesWith<TAttribute>(bool inherit) where TAttribute : System.Attribute
        {
            return from a in AppDomain.CurrentDomain.GetAssemblies()
                   from t in a.GetTypes()
                   where t.IsDefined(typeof(TAttribute), inherit)
                   select t;
        }
#endif
    }
}
